watchdoge 0.1.8 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 31dedfc4a4c2e9534672ab388d89afeccb56e9855b5e14e9c454f9b4b0750670
4
- data.tar.gz: c91210715bedf6187b55e543ff95f82a4390457bd9a4c83026c36d1ab130175b
3
+ metadata.gz: db9eab410f530c1dd00de8bfb39a4cfaa86d3e41aa86105d776c47e8c68ad9cb
4
+ data.tar.gz: 3196f93d3121f1aaafe6a4dfea5fc702dfbe54c4a985dfdd6b4f08abc3e515af
5
5
  SHA512:
6
- metadata.gz: aead7efe871204a654be431a18eacbd5eb1b22e299f0f2eb6d941022d58826fb0cb5024623dff704758558a07a2531c6d3e825409a0f5d4c74b66b5115ee29b4
7
- data.tar.gz: e255c5c965a8a3dcaa8709a762a07127d9aa6850b3f06ecacfb67dac9accca785fd4a84e48fd53bb0988b738a27b0a29a6ca06a714f1e39dd26e3fe3201f2a00
6
+ metadata.gz: ef68aed278dc48dd7eac239a9c91bbaf532b010f4bb28f4c32ddbd3c57d3dd271a26e7c087e86bf2d7b64abe37dc73a2c51c1990e3a73882ce41f05bdbc9f2ea
7
+ data.tar.gz: a9d02b67e9534ccf26047f4eb260b738251a68a92971fa7333689220dc13e1c4b089c36b0d507c950543cc3fbeff5d7adc3beb3602c32ecb373102fa868e7197
@@ -0,0 +1,35 @@
1
+ require 'pry'
2
+ require 'net_http_ssl_fix'
3
+
4
+ require 'chunky_png'
5
+ require 'json'
6
+ require 'net/http'
7
+ require 'net/http/post/multipart'
8
+ require 'uri'
9
+
10
+ module WatchDoge
11
+ module Notification
12
+ class Base
13
+ def initialize opt
14
+ @message_queue = []
15
+ end
16
+
17
+ def push message
18
+ @message_queue << message
19
+ end
20
+
21
+ def flush
22
+ @message_queue.each do |message|
23
+ case message
24
+ when String
25
+ puts message
26
+ when ChunkyPNG::Image
27
+ File.write 'image.png', message.to_blob
28
+ when WatchDoge::PixelTest
29
+ File.write 'image.png', message.diff.to_blob
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -9,40 +9,47 @@ require 'uri'
9
9
 
10
10
  module WatchDoge
11
11
  module Notification
12
- class GitlabRepo
12
+ class GitlabRepo < WatchDoge::Notification::Base
13
13
  def initialize opt
14
+ super
15
+
14
16
  @host = opt[:host] || ENV['CI_API_V4_URL']
15
17
  @project_id = opt[:project_id] || ENV['CI_PROJECT_ID']
16
18
  @source_branch = opt[:source_branch] || ENV['CI_COMMIT_REF_NAME']
17
19
 
18
20
  @private_token = opt[:private_token]
19
-
20
- @message_queue = []
21
- end
22
-
23
- def push message
24
- @message_queue << message
25
21
  end
26
22
 
27
23
  def flush
28
- @message_queue.each do |message|
29
- iid = get_latest_request_iid
30
-
31
- return if iid.nil?
32
-
33
- case message
34
- when String
35
- post_discussion request_iid: iid, message: message
36
- when ChunkyPNG::Image
37
- image_blob = message.to_blob
38
- res = upload_image image_blob
39
- image_link = "![image](#{ENV['CI_PROJECT_URL']}#{res['url']})"
40
- post_discussion request_iid: iid, message: image_link
41
-
42
- # TODO: should add WatchDoge::Diff as pair of before/after iamges
43
- # when WatchDoge::Diff
24
+ iid = get_latest_request_iid
25
+
26
+ @message_queue = [] if iid.nil?
27
+
28
+ table = markdown_table do |table_context|
29
+ @message_queue.each do |message|
30
+ case message
31
+ when String
32
+ post_discussion request_iid: iid, message: message
33
+ when ChunkyPNG::Image
34
+ upload_link = upload_image message
35
+ link = md_img_link upload_link
36
+
37
+ post_discussion request_iid: iid, message: link
38
+ when WatchDoge::PixelTest
39
+ before = md_img_link upload_image(message.before)
40
+ after = md_img_link upload_image(message.after)
41
+ diff = md_img_link upload_image(message.diff)
42
+
43
+ table_context << markdown_table_row(before, after, diff)
44
+ end
44
45
  end
46
+
47
+ table_context
45
48
  end
49
+
50
+ @message_queue = []
51
+
52
+ post_discussion request_iid: iid, message: table
46
53
  end
47
54
 
48
55
  def post_discussion request_iid:, message:
@@ -54,11 +61,11 @@ module WatchDoge
54
61
  "PRIVATE-TOKEN": @private_token
55
62
  end
56
63
 
57
- def upload_image blob
64
+ def upload_image image
58
65
  uri = project_uri "/uploads"
59
66
 
60
67
  req = Net::HTTP::Post::Multipart.new uri.path, {
61
- file: UploadIO.new(StringIO.new(blob), 'image/png', 'image.png')
68
+ file: UploadIO.new(StringIO.new(image.to_blob), 'image/png', 'image.png')
62
69
  }
63
70
 
64
71
  req.add_field("PRIVATE-TOKEN", @private_token)
@@ -67,7 +74,7 @@ module WatchDoge
67
74
  res = http.request(req).body
68
75
  end
69
76
 
70
- JSON.parse(res)
77
+ JSON.parse(res)['url']
71
78
  end
72
79
 
73
80
  def get_latest_request_iid
@@ -87,6 +94,10 @@ module WatchDoge
87
94
 
88
95
  private
89
96
 
97
+ def md_img_link link
98
+ "![image](#{ENV['CI_PROJECT_URL']}#{link})"
99
+ end
100
+
90
101
  # markdown_table do |context|
91
102
  def markdown_table
92
103
  "<table>
@@ -99,6 +110,14 @@ module WatchDoge
99
110
  </table>"
100
111
  end
101
112
 
113
+ def markdown_table_row before, after, diff
114
+ "<tr>
115
+ <td>#{before}</td>
116
+ <td>#{after}</td>
117
+ <td>#{diff}</td>
118
+ </tr>"
119
+ end
120
+
102
121
  def project_uri path
103
122
  URI(@host + "/projects/#{@project_id}#{path}")
104
123
  end
@@ -8,15 +8,11 @@ module WatchDoge
8
8
  module Notification
9
9
  class Mattermost
10
10
  def initialize args
11
+ super
12
+
11
13
  @host = args[:host]
12
14
  @channel_id = args[:channel_id]
13
15
  @auth_token = args[:auth_token]
14
-
15
- @message_queue = []
16
- end
17
-
18
- def push message
19
- @message_queue << message
20
16
  end
21
17
 
22
18
  def flush
@@ -26,6 +22,8 @@ module WatchDoge
26
22
  post matter_most_meta(message)
27
23
  when ChunkyPNG::Image
28
24
  post_file matter_most_meta(message)
25
+ when WatchDoge::PixelTest
26
+ post_file matter_most_meta(message.diff)
29
27
  end
30
28
  end
31
29
  end
@@ -1,19 +1,10 @@
1
- require 'chunky_png'
2
- require 'json'
3
- require 'net/http'
4
- require 'uri'
5
-
6
1
  module WatchDoge
7
2
  module Notification
8
3
  class SlackWebhook
9
4
  def initialize opt
10
- @incoming_url = opt[:incoming_url]
11
-
12
- @message_queue = []
13
- end
5
+ super
14
6
 
15
- def push message
16
- @message_queue << message
7
+ @incoming_url = opt[:incoming_url]
17
8
  end
18
9
 
19
10
  def flush
@@ -36,6 +27,14 @@ module WatchDoge
36
27
  when ChunkyPNG::Image
37
28
  data = ['data:image/png;base64,', message.to_blob].pack('A*m').gsub(/\n/, '')
38
29
 
30
+ {
31
+ attachments: [{
32
+ image_url: data
33
+ }]
34
+ }
35
+ when WatchDoge::PixelTest
36
+ data = ['data:image/png;base64,', message.diff.to_blob].pack('A*m').gsub(/\n/, '')
37
+
39
38
  {
40
39
  attachments: [{
41
40
  image_url: data
@@ -21,6 +21,8 @@
21
21
  # end
22
22
 
23
23
  # built-in sources
24
+ require 'watchdoge/notification/base'
25
+
24
26
  require 'watchdoge/notification/slack_webhook'
25
27
  require 'watchdoge/notification/mattermost'
26
28
  require 'watchdoge/notification/gitlab_repo'
@@ -51,7 +53,9 @@ module WatchDoge
51
53
  def sources
52
54
  @sources ||= WatchDoge.configuration.notifications
53
55
 
54
- raise "can't find notification sources in configuration" if @sources.empty?
56
+ @sources = {
57
+ base: {}
58
+ } if @sources.empty?
55
59
 
56
60
  @sources.each do |klass_sym, source_args|
57
61
  sources_map[klass_sym] ||=
@@ -0,0 +1,61 @@
1
+ # generating diff image of two input image
2
+
3
+ # usage:
4
+ # diff_image = WatchDoge::PixelTest.diff(chunky_png_image, another_chunky_png_image)
5
+ # WatchDoge::PixelTest.new diff_image, before:
6
+
7
+ # spec:
8
+ # 1. input only accept ChunkyPNG::Image, output image is also ChunkyPNG::Image
9
+ # 2. able to testing RGBA pixel by pixel. then blending with mask color if diff detected
10
+
11
+ # todo: should improve testing boundary for more accurate diff imagenot.
12
+
13
+ module WatchDoge
14
+ class PixelTest
15
+ def self.diff input_image, reference_image, opacity: 0.7, mask_base_color: "#F163FF"
16
+ return nil if input_image.pixels.hash == reference_image.pixels.hash
17
+
18
+ mask_color = mask_base_color.concat (opacity * 256).to_i.to_s(16).upcase
19
+
20
+ dup_input_image = input_image.dup
21
+
22
+ input_image.height.times do |y|
23
+ pixels = input_image.row(y)
24
+
25
+ if y >= reference_image.height
26
+ pixels.each_with_index do |pixel, x|
27
+ dup_input_image.compose_pixel(x, y, mask_color)
28
+ end
29
+ else
30
+ reference_pixels = reference_image.row(y)
31
+
32
+ next if (pixels.hash == reference_pixels.hash)
33
+
34
+ pixels.each_with_index do |pixel, x|
35
+ if pixels[x] != reference_pixels[x]
36
+ dup_input_image.compose_pixel(x, y, reference_pixels[x])
37
+ dup_input_image.compose_pixel(x, y, mask_color)
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ dup_input_image
44
+ end
45
+
46
+ attr_reader :diff
47
+ attr_reader :before
48
+ attr_reader :after
49
+
50
+ def initialize input, reference
51
+ @before = reference
52
+ @after = input
53
+
54
+ @diff = self.class.diff input, reference
55
+ end
56
+
57
+ def diff?
58
+ @diff
59
+ end
60
+ end
61
+ end
@@ -63,15 +63,10 @@ module WatchDoge
63
63
  when :regression
64
64
  puts " -> compare reference images on worker #{@worker}"
65
65
  reference_image = WatchDoge::Regression::Utils.load_png self.reference_image
66
- cycle_image = WatchDoge::Regression::Utils.load_png @worker.screenshot.png
67
- diff = WatchDoge::ImageDiff.diff(cycle_image, reference_image)
68
- if diff
69
- if ENV['WATCHDOGE_DEBUG']
70
- WatchDoge::Notification.push cycle_image
71
- WatchDoge::Notification.push reference_image
72
- end
73
- WatchDoge::Notification.push diff
74
- end
66
+ input_image = WatchDoge::Regression::Utils.load_png @worker.screenshot.png
67
+ pixel_test = WatchDoge::PixelTest.new(input_image, reference_image)
68
+
69
+ WatchDoge::Notification.push pixel_test if pixel_test.diff?
75
70
  end
76
71
  end
77
72
 
@@ -32,6 +32,7 @@ module WatchDoge
32
32
  end
33
33
 
34
34
  WatchDoge.hooks.after_regression.each { |t| t.call }
35
+ WatchDoge::Notification.flush
35
36
  end
36
37
  end
37
38
 
@@ -1,4 +1,4 @@
1
1
  # Version of WatchDoge
2
2
  module WatchDoge
3
- VERSION = '0.1.8'
3
+ VERSION = '0.1.9'
4
4
  end
data/lib/watchdoge.rb CHANGED
@@ -4,7 +4,7 @@ require 'watchdoge/configuration'
4
4
  require 'watchdoge/cookie_pool'
5
5
  require 'watchdoge/worker'
6
6
  require 'watchdoge/notification'
7
- require 'watchdoge/image_diff'
7
+ require 'watchdoge/pixel_test'
8
8
  require 'watchdoge/regression'
9
9
  require 'watchdoge/rails/railtie' if defined?(Rails)
10
10
  require 'watchdoge/rails/generator' if defined?(Rails)
data/watchdoge.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'watchdoge'
3
- s.version = '0.1.8'
3
+ s.version = '0.1.9'
4
4
  s.date = '2019-07-22'
5
5
  s.summary = "dogi"
6
6
  s.description = "WatchDoge is Ruby on Rails friendly frontend regression test tool"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: watchdoge
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shen Lee
@@ -114,11 +114,12 @@ files:
114
114
  - lib/watchdoge.rb
115
115
  - lib/watchdoge/configuration.rb
116
116
  - lib/watchdoge/cookie_pool.rb
117
- - lib/watchdoge/image_diff.rb
118
117
  - lib/watchdoge/notification.rb
118
+ - lib/watchdoge/notification/base.rb
119
119
  - lib/watchdoge/notification/gitlab_repo.rb
120
120
  - lib/watchdoge/notification/mattermost.rb
121
121
  - lib/watchdoge/notification/slack_webhook.rb
122
+ - lib/watchdoge/pixel_test.rb
122
123
  - lib/watchdoge/rails/generator.rb
123
124
  - lib/watchdoge/rails/railtie.rb
124
125
  - lib/watchdoge/regression.rb
@@ -1,47 +0,0 @@
1
- # generating diff image of two input image
2
-
3
- # usage:
4
- # diff_image = WatchDoge::ImageDiff.diff(chunky_png_image, another_chunky_png_image)
5
-
6
- # spec:
7
- # 1. input only accept ChunkyPNG::Image, output image is also ChunkyPNG::Image
8
- # 2. able to testing RGBA pixel by pixel. then blending with mask color if diff detected
9
-
10
- # todo: should improve testing boundary for more accurate diff imagenot.
11
-
12
- module WatchDoge
13
- module ImageDiff
14
- class << self
15
- def diff input_image, reference_image, opacity: 0.7, mask_base_color: "#F163FF"
16
- return nil if input_image.pixels.hash == reference_image.pixels.hash
17
-
18
- mask_color = mask_base_color.concat (opacity * 256).to_i.to_s(16).upcase
19
-
20
- dup_input_image = input_image.dup
21
-
22
- input_image.height.times do |y|
23
- pixels = input_image.row(y)
24
-
25
- if y >= reference_image.height
26
- pixels.each_with_index do |pixel, x|
27
- dup_input_image.compose_pixel(x, y, mask_color)
28
- end
29
- else
30
- reference_pixels = reference_image.row(y)
31
-
32
- next if (pixels.hash == reference_pixels.hash)
33
-
34
- pixels.each_with_index do |pixel, x|
35
- if pixels[x] != reference_pixels[x]
36
- dup_input_image.compose_pixel(x, y, reference_pixels[x])
37
- dup_input_image.compose_pixel(x, y, mask_color)
38
- end
39
- end
40
- end
41
- end
42
-
43
- dup_input_image
44
- end
45
- end
46
- end
47
- end